About Endpoints
An endpoint is the communications path between your application and an endpoint provider, which is a layered set of protocols that define how data and other information are exchanged between you and a remote client. The endpoint consists of a set of data structures, maintained by Open Transport, that specify the components of the endpoint provider, and the manner in which the provider is to operate. In the process of opening an endpoint, you configure the endpoint provider and specify the protocol or set of protocols you want to use to transfer data and, if required, the hardware link. The chapter "Configuration Management" in this book explains how you specify the software and hardware support your application requires. Whether you specify a single protocol or a layered set of protocols, the type of service provided by the highest-level protocol defines the type of the endpoint. For example, if you specify the AppleTalk Transaction Protocol (ATP), which offers connectionless transaction-based service, the endpoint is a connectionless transaction-based endpoint.When you open an endpoint, Open Transport creates a data structure that contains information about the services the endpoint provider offers, the limits on the size of data it can send and receive, the size of internal buffers used to hold data, the current state of the endpoint, and so on. Open Transport obtains this information from the particular protocol implementations that you specify when you configure the endpoint provider. You can access information in some fields of this structure by calling functions that return information about the endpoint provider. Other fields of the structure are private and can be accessed only by Open Transport.
Opening an endpoint also creates an endpoint reference, an number that uniquely identifies this endpoint and that you must specify when calling any function relating to this endpoint.
Before you can use the endpoint to transfer data, you must bind the endpoint--that is, you must associate the endpoint with a logical address. Depending on the protocol you use, you can specify this address as a symbolic name or as a network address. Specific address binding rules and address formats also vary with the protocol you use. In general, you cannot bind more than one connectionless endpoint to an address, but you can bind several connection-oriented endpoints to a single address.
Open Transport functions that you can use only with endpoints are called endpoint functions. You use endpoint functions to create and bind an endpoint, to obtain information about an endpoint, to establish and break down connections, and to transfer data. What functions you can call for an endpoint depends on the type of the endpoint and on its state. The behavior of a function is determined by the endpoint's mode of operation. In order to write Open Transport applications that behave in a reliable and predictable manner, it is important that you understand how these factors affect the behavior of an endpoint provider. The rest of this section describes the different types of endpoints, describes the effect of an endpoint's mode of operation on the behavior of endpoint functions, and explains how Open Transport uses information about endpoint states to manage endpoints.
Endpoint Types and Mode of Service
There are four types of endpoints, each offering a different mode of service:
As you can tell from the foregoing description, in Open Transport there is no such thing as a connectionless endpoint. It would have to be either a connectionless transaction-based endpoint or a connectionless transactionless endpoint. However, because there are issues that affect endpoints inasmuch as they are connectionless and not connection-oriented or transactionless and not transaction-based, when this chapter identifies an endpoint using only one service name, you should assume that the endpoint can be in one of two modes of service. Thus, the term transaction-based endpoint can refer either to a connectionless transaction-based endpoint or to a connection-oriented transaction-based endpoint.
- connection-oriented transactionless service
Either endpoint can initiate this type of service. It allows for the transfer of very large amounts of data with guaranteed data delivery and a reliable data stream.
- connection-oriented transaction-based service
Either endpoint can initiate the connection, but only the endpoint sending the request can initiate a transaction. Using this service, you can conclude an unlimited number of parallel transactions. This service guarantees delivery and can detect duplicate sends.
- connectionless transactionless service
Either endpoint can initiate this type of service. Some protocols can calculate checksums for incoming packets, but generally this service provides only best-effort delivery and allows the transfer of relatively small amounts of data at one time.
- connectionless transaction-based service
Only the endpoint sending a request can initiate this type of service. It allows for the transfer of larger amounts of data, provides some error checking, detects duplicate sends, and guarantees that response packets are delivered in the order sent.
The chapter "Introduction to Open Transport" in this book defines and describes the different services that each type of endpoint offers and explains some of the criteria you might use for selecting a specific type. The documentation for the protocol you are using provides information about how a mode of service is implemented for your endpoint and the options that you can use to fine-tune its behavior. The section "Using Endpoints" beginning on page 3-18 describes how you use endpoint functions to implement these services. However, before you read that section, you might find it helpful to understand the naming conventions used for endpoint functions because these are directly related to an endpoint's mode of service. These conventions are described in the next section.
Naming Conventions for Endpoint Functions
You can use endpoint functions that return information about the endpoint's state, address, mode of execution, or mode of operation with all endpoint types. However, which endpoint functions you can call to transfer data depends on the type of the endpoint. There is no single function that you can use to send data or to receive data. For each type of endpoint you open, you must use a send function that is specific to that type. For example, when you send data using a connectionless transactionless endpoint, you call theOTSndUData
function; when you send data using a connection-oriented transactionless endpoint, you call theOTSnd
function. Table 3-1 presents a summary of the function names for functions used to transfer data. The functions are grouped together based on the endpoint's mode of service. Look over this table briefly and see if you can spot the distinguishing trait for each group of names.The following bulleted items explain the rationale for the conventions used to name the different groups of functions:
Of course, you can use the functions that establish and tear down connections only with connection-oriented endpoints. These functions suggest their use in their names: for example,
- Transaction-based endpoints send and receive requests and replies. If a function name contains the string "Request" or "Reply," you use the function for a transaction-based endpoint; for example,
OTSndURequest
orOTSndRequest
.- Transactionless endpoints send and receive data, not requests or replies. If a function name contains the string "Snd" or "Rcv" but does not contain "Request" or "Reply," you use the function for a transactionless endpoint; for example,
OTSnd
orOTSndUData
.- Connectionless endpoints must include the destination address as a parameter to every send operation and the source address as a parameter to every receive operation. This is signalled by the letter "U" in the name of a function. Thus, you call the
OTSndUData
function for a connectionless transactionless endpoint, but you call theOTRcvURequest
function for a connectionless transaction-based endpoint.- Connection-oriented endpoints do not need to include addresses in send and receive operations because establishing the connection also determines the addresses, which do not change during a session. The names of functions that can be called for connection-oriented endpoints are exactly the same as for connectionless endpoints except that the "U" is omitted. Thus, you call the
OTSnd
function for a connection-oriented transactionless endpoint and theOTSndRequest
function for a connection-oriented transaction-based endpoint.
OTConnect
orOTSndDisconnect
. Connection-oriented endpoints support two kinds of disconnects: abortive disconnects and orderly disconnects. An abortive disconnect breaks a connection immediately, even if this were to result in loss of data; an orderly disconnect allows an endpoint to send all data remaining in its send buffer before it breaks a connection. These two kinds of disconnects are reflected in the names of the functions used:OTSndDisconnect
for an abortive disconnect andOTSndOrderlyDisconnect
for an orderly disconnect.Endpoint Options
The goal of Open Transport is to allow one type of endpoint to communicate with the same type of endpoint (or with a remote client offering the same mode of service) simply by having the application reconfigure the endpoint provider so as to use the protocol of the remote client. Reconfiguring the endpoint provider would require very minimal changes to the application and consequently make your application virtually independent of the underlying transport used to transfer data. Achieving transport independence, however, also means being willing to forego any special advantages or features that a protocol has to offer. If it is not possible for you to do without these features, you can use options to take advantage of protocol-specific features. An option is a value that you can set for an endpoint, which links the behavior of your application to the specific protocol that you have used to configure the endpoint provider. By using options, you can take advantage of a service that is unique to a protocol.In general, the use of options decreases the portability of your application. When you open an endpoint, the endpoint provider creates a buffer containing default option values that it chooses to ensure maximum portability across protocol families and system platforms. It is recommended that you use these values rather than setting different values. However, if you need to customize transport services, you might need to specify different option values. Selecting alternate option values begins a process called option negotiation. During this process, option values are negotiated between an endpoint and its provider or, if the option affects a connection or transaction, between a local and remote endpoint and their providers. The providers must conclude this negotiation process before you can use an endpoint to transfer data. Besides noting those instances in which you can specify option information when calling endpoint functions, this chapter provides no information about options. For detailed information about options and for a description of the
OTOptionManagement
endpoint function, see the chapter "Option Management" in this book.Modes of Operation
An endpoint provider, like other Open Transport providers, can also be characterized by its mode of operation, which determines
The chapter "Providers" also introduces these concepts and describes the functions you use to get and set a provider's mode of operation. The rest of this section contains a more detailed discussion of how blocking and acknowledging sends specifically affect endpoint functions.
- whether the functions used for that endpoint provider execute synchronously or asynchronously.
The chapter "Providers" in this book contains a detailed discussion of the issues involved in selecting one or another mode of execution. The section "Handling Events for Endpoints," beginning on page 3-22 offers additional information about how an endpoint provider's mode of execution specifically affects endpoint functions.
- whether the provider blocks or waits when sending or receiving data and
- whether the provider copies data that you want to send before sending it.
Blocking
If an endpoint provider is blocking, functions that you use to send or receive data do not complete until they actually write or read the amount of data that you have specified should be written or read.
If you are sending data faster than the network can handle it, this gives rise to flow-control restrictions. If an endpoint is blocking, a send function waits until flow-control restrictions are lifted before it executes. A send function must also wait if an endpoint provider cannot deal with a request immediately, but must queue the request before it is able to handle it.
- You specify the amount of data you expect to write, by setting the
len
field of aTNetBuf
structure to the length of the data in the data buffer. If the size of data in the data buffer is smaller than the size you specified in thelen
field, the function will not complete. Under the same circumstances, if the endpoint is not blocking, the function will complete.- You specify the amount of data you expect to read, by setting the
maxlen
field of aTNetBuf
structure. If the size of the incoming data is smaller than the value specified in themaxlen
field, the function will not complete. Under the same circumstances, if the endpoint is not blocking, the function will complete.
If an endpoint provider is nonblocking or asynchronous and a send function cannot complete due to flow-control restrictions, the function returns with the
kOTFlowErr
result or it returns a positive integer. If the function returns thekOTFlowErr
result, this means that it has not been able to send any data; if it returns a positive integer, this represents the amount of data it has been able to send. When flow-control restrictions are lifted, the provider issues aT_GODATA
orT_GOEXDATA
event. Upon receiving this event, you should execute the send function again to send the remaining data.If an endpoint provider is nonblocking or asynchronous and a send function cannot complete because the request for function execution would have to be queued, the function returns with the
kEAGAINErr
orkEWOULDBLOCKErr
result. You should try to execute the command later.If an endpoint provider is in synchronous blocking mode and a receive function cannot complete because the data has not arrived, the function does not return until either data actually arrives and the size of the data is equal to the maximum size you specified for the receive buffer, or data arrives and the
T_MORE
flag is not set (there's an EOM marker, which means that you have retrieved all the data sent). If an endpoint provider is nonblocking and a receive function cannot complete because data has not yet arrived, the function returns with thekOTNoDataErr
. You should try calling the function again later.An endpoint provider is nonblocking unless you use the
OTSetBlocking
function to change its mode of operation.Acknowledging Sends
You can also affect the behavior of functions that send data by specifying that the endpoint provider acknowledge sends. By default, Open Transport does not acknowledge the completion of send operations. This means that when you call a function to send data, Open Transport copies the data from the client buffer into a different buffer and then sends it. If you ask Open Transport to acknowledge sends, it relies on the fact that your data buffer will remain stable until the endpoint provider can actually send the data. After it sends the data, the provider calls your notifier function passingT_MEMORYRELEASED
for thecode
parameter, a pointer to the buffer that was sent in thecookie
parameter, and the size of the buffer in theresult
parameter.Endpoint States
Each endpoint has an attribute known as its endpoint state. An endpoint state governs which endpoint functions you can call for the endpoint. For example, if you open an endpoint but do not bind it, it is in theT_UNBND
state and the only two functions you can call for the endpoint areOTCloseProvider
orOTBind
. The endpoint's mode of service determines the possible states an endpoint can be in while it is transferring data. For example, a connectionless endpoint can only transfer data while it is in theT_IDLE
state; a connection-oriented endpoint can only transfer data while it is in theT_DATAXFER
state. Table 3-2 describes possible endpoint states for connectionless and connection-oriented endpoints and suggests in parentheses an English equivalent for the name of each constant.Figure 3-1 shows a diagram illustrating the possible endpoint states for a connectionless endpoint.
Figure 3-1 Possible endpoint states for a connectionless endpoint
A connectionless endpoint can be in one of three states:
T_UNINIT,T_UNBND
, orT_IDLE
. Before you open the endpoint, it is in theT_UNINIT
state. After you open the endpoint but before you bind it, it is in theT_UNBND
state. After you bind the endpoint, it is in theT_IDLE
state and is ready to transfer data. A connectionless transactionless endpoint would use theOTSndUData
orOTRcvUData
functions to transfer data; a connectionless transaction-based endpoint would use theOTSndURequest
,OTRcvURequest
,OTSndUReply
, andOTRcvUReply
functions to transfer data. When the endpoint finishes transferring data, you must first unbind the endpoint--that is, dissociate the endpoint from its address. At this stage, the endpoint returns to theT_UNBND
state. Then you can close the endpoint, at which time the endpoint returns to theT_UNINIT
state.Figure 3-2 shows a state diagram illustrating the possible endpoint states for a connection-oriented endpoint.
Figure 3-2 Possible endpoint states for a connection-oriented endpoint
Like a connectionless endpoint, a connection-oriented endpoint is in the
T_UNINIT
state until you open it and then, in theT_UNBND
state until you bind it. After you bind an endpoint but before you inititate a connection, an endpoint is in theT_IDLE
state.During the connection process, the endpoint provider initiating the connection, known as the active peer, calls the
OTConnect
function to request a connection. At this point, the active peer is in theT_OUTCON
state. The endpoint provider listening for a connection request, known as the passive peer, calls theOTListen
function to read an incoming request. After it has read the request, the passive peer changes to theT_INCON
state. It can now either accept the connection using theOTAccept
function or reject the connection using theOTSndDisconnect
function. If the endpoint accepts the connection, it changes to theT_DATAXFER
state; if it rejects the connection it goes back to theT_IDLE
state.The active peer must acknowledge the response using the
OTRcvConnect
function (for a connection that has been accepted) or theOTRcvDisconnect
function (for a connection that has been rejected). Calling theOTRcvConnect
function establishes the connection and places the active peer in theT_DATAXFER
state. Calling theOTSndDisconnect
function rejects the connection and places the active peer in theT_IDLE
state. After they are connected, endpoints can transfer data using simple send and receive operations or using transaction requests and replies, depending on whether the endpoint is transactionless or transaction-based.When the client applications have finished transferring data, they must tear down the connection by using an orderly disconnect process if possible. That is, the active peer, should check to see whether the protocol supports an orderly disconnect. If it does, the active peer initiates this process by calling the
OTSndOrderlyDisconnect
function. This places the active peer in theT_OUTREL
state. It also creates a pendingT_ORDREL
event for the other endpoint. The passive peer can retrieve the event using a notifier function or using theOTLook
function. It must then acknowledge receiving the disconnection request by calling theOTRcvOrderlyDisconnect
function. Then it must tear down its side of the connection by also calling theOTSndOrderlyDisconnect
function, which the other side must also acknowledge. Disconnecting the endpoints places them in theT_IDLE
state again, and you can reconnect or close them.Open Transport uses endpoint state information to manage endpoints. Consequently, it is crucial that you call functions in the right sequence and that you call functions to acknowledge receipt of data as well as of connection and disconnection requests. Sending these acknowledgments is necessary to leave the endpoint in an appropriate state for further processing. In your application, you can sometimes use the
OTGetEndpointState
function to determine an endpoint's state, which is one more way to test for successful completion of a function.Table 3-3 lists the functions that can change an endpoint's state and specifies what the resulting state is depending on whether the function succeeds or fails.
The arrival of an asynchronous event can also change the state of an endpoint. Table 3-4 shows the state of the endpoint before the event is received and the state of the endpoint after the event is consumed. An event is consumed or cleared when your application acknowledges receipt of the event. For example, if you get a
T_LISTEN
event, you call theOTListen
function; after you get aT_DISCONNECT
event, you call theOTRcvDisconnect
function.The section "Handling Events for Endpoints" on page 3-22 lists the asynchronous events that a provider can issue and the functions you must call to clear these events.
Transport Service Data Units
The main purpose of endpoints is to transfer data. The terms transport service data unit and expedited transport service unit are used to describe the size and kind of data that a particular endpoint can handle when it is transferring data in discrete units known as datagrams. Not all protocols use transport service data units to transfer data.A transport service data unit (TSDU), whether it is normal or expedited, refers to the largest piece of data that an endpoint can transfer with boundaries and content preserved unchanged. Different types of endpoints and different endpoint implementations support different size TSDUs.
An expedited transport service data unit (ETSDU), refers to the largest piece of expedited data than an endpoint can transfer. Expedited data is considered to be urgent. An endpoint provider that can handle expedited data guarantees that this data takes precedence over any other normal data that is being transmitted. Not all endpoint providers can transfer expedited data. Usually, connection-oriented and transaction-based endpoints require the use of expedited data for control or attention messages, and therefore the implementation of these types of endpoints often supports the transfer of expedited data.
When you open an endpoint, Open Transport creates an endpoint information structure, a
TEndpointInfo
structure, that you can examine to find out whether the endpoint supports normal or expedited data and the maximum size of this data. The section "Obtaining Information About Endpoints," beginning on page 3-21 explains how you examine this structure to find out this information.